/*jslint */
/*global Class */

// TODO: добавить распаралеливание !!!

/**
 * Простейший класс отложенных действий.
 *
 * @class
 * @name Deferred
 * @extends Class
 */
var Deferred = Class.$extend({

    /**
     * Список действий.
     *
     * @private
     * @field
     * @name Deferred#actions
     * @type {Function[]|null}
     */
    actions : null,

    /**
     * Обработчик завершения.
     *
     * @private
     * @field
     * @name Deferred#complete
     * @type {Function|null}
     */
    complete : null,

    /**
     * Конструктор.
     *
     * @public
     * @function
     * @name Deferred#$init
     * @param {Function[]} actions Список отложенных действий.
     * @param {Function} complete Обработчик завершения.
     * @return {void}
     */
    $init : function (actions, complete) {
        'use strict';
        var index, length;
        if (!(actions instanceof Array)) {
            throw new TypeError('');
        }
        if (typeof complete !== 'function') {
            throw new TypeError('Complete callback is not a function');
        }
        length = actions.length;
        this.complete = complete;
        this.actions = [];
        for (index = 0; index < length; index += 1) {
            // Добавляем каждое действие с проверкой.
            this.add(actions[index]);
        }
    },

    /**
     * Добавление действия.
     *
     * @public
     * @function
     * @name Deferred#add
     * @param {Function|Function[]} action
     * @return {void}
     */
    add : function (action) {
        'use strict';
        var index, length;
        if (action instanceof Array) {
            length = action.length;
            // Добавляем параллельные действия.
            for (index = 0; index < length; index += 1) {
                if (typeof action[index] !== 'function') {
                    throw new TypeError('Subaction is not a function');
                }
            }
        } else if (typeof action !== 'function') {
            // Добавляем последовательные действия.
            throw new TypeError('Action is not a function');
        }
        this.actions.push(action);
    },

    /**
     * Завершение процесса с ошибкой.
     *
     * @private
     * @function
     * @name Deferred#error
     * @see Deferred#success
     * @param {String} message Сообщение об ошибке.
     * @return {void}
     */
    error : function (message) {
        'use strict';
        this.actions = []; // Уничтожаем список действий.
        this.complete(new Error(String(message || '')));
    },

    /**
     * Успешное продолжение процесса.
     *
     * @private
     * @function
     * @name Deferred#success
     * @see Deferred#error
     * @return {void}
     */
    success : function () {
        'use strict';
        var self    = this,                 // Ссылка на текуший объект.
            action  = this.actions.shift(), // Текущее действие.
            success = function () {
                self.success();
            },
            error   = function (message) {
                self.error(message);
            };
        if (typeof action === 'function') {
            // Вызов действия.
            action(success, error);
        } else {
            // Успешное завершение.
            this.complete();
        }
    },

    /**
     * Запуск процесса.
     *
     * @public
     * @function
     * @name Deferred#run
     * @return {void}
     */
    run : function () {
        'use strict';
        this.success();
    }

});
